PlotlyのPython用ライブラリで3Dプロットを試してみた
データアナリティクス事業本部の鈴木です。
今回は、PlotlyのPython用ライブラリを使って3次元表面を描画する方法をまとめてみました。
Plotlyの公式ドキュメントで3Dプロットを紹介している、『3D Surface Plots』を参考にしています。
ドキュメントでは描画の設定の記載もありますが、この記事ではどのようなインプットをすると3Dプロットができるのかというところを中心にご紹介します。
また、ドキュメントに載っていない関数も描いてみようと思い、1例だけですが別の関数も描いてみました。
検証環境
Jupyter Docker Stacksのdatascience-notebookイメージにPlotlyをインストールして検証しました。バージョンなどは以下になります。
- イメージ:jupyter/datascience-notebook
- Plotly 5.6.0
使い方を確認してみる
ドキュメントに紹介されている2つの例を試してみました。
どちらもplotly.graph_objects.Surfaceを作成し、plotly.graph_objects.Figureに渡して表示する流れになります。
まず、Surface
を配列から作成して、どのようにインスタンスを作るか確認します。
以下のコードを作成し、実行することで、どのような3Dプロットができるか確認します。
# https://plotly.com/python/3d-surface-plots/ # を2022/02/15に改変しました。 import plotly.graph_objects as go sur = go.Surface( contours = { "x": {"show": True, "start": 1.5, "end": 2, "size": 0.04, "color":"white"}, "z": {"show": True, "start": 0.5, "end": 0.8, "size": 0.05} }, x = [1,2,3,4,5], y = [1,2,3,4,5], z = [ [0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0], [1, 0, 1, 0, 1], [0, 1, 0, 1, 0] ]) fig = go.Figure(sur) fig.update_layout( scene = { "xaxis": {"nticks": 20}, "zaxis": {"nticks": 4}, 'camera_eye': {"x": 0, "y": -1, "z": 0.5}, "aspectratio": {"x": 1, "y": 1, "z": 0.2} }) fig.show()
実行すると以下のような3Dプロットが描画されます。3次元でぐるぐる回転させることが可能です。
Surface
のx
とy
に渡した配列と、z
に渡した2次元配列の対応する値が3Dプロットの座標に各々対応しています。
次にpandasのDataFrameから作成する場合も確認しておきます。この場合は、values
で2次元配列にしてから、先ほどと同じようにSurface
に渡す形になります。
# https://plotly.com/python/3d-surface-plots/ # を2022/02/15に改変しました。 import plotly.graph_objects as go import pandas as pd # Read data from a csv z_data = pd.read_csv('https://raw.githubusercontent.com/plotly/datasets/master/api_docs/mt_bruno_elevation.csv', index_col=0) fig = go.Figure(data=[go.Surface(z=z_data.values)]) fig.update_layout(title='Mt Bruno Elevation', autosize=False, width=500, height=500, margin=dict(l=65, r=50, b=65, t=90)) fig.show()
実行すると以下のような3Dプロットが描画されます。
x
およびy
を指定しない場合は、x軸とy軸が0からになります。
オリジナルの例を試してみる
使い方が分かったので、自分でも例を作ってみました。
今回は鞍点がある関数を表示してみました。
以下のように、描画したい関数f
を定義し、適当なx
とy
の範囲でz
の値を計算してSurface
に渡します。
# 表示したい関数 def f(x, y): return x*x - y*y # 表示するデータの作成 xs = [x for x in range(-10, 10)] ys = [y for y in range(-10, 10)] zs = [[f(x, y) for x in xs] for y in ys] # 表示 sur = go.Surface( contours = { "x": {"show": True, "start": 1.5, "end": 2, "size": 0.04, "color":"white"}, "z": {"show": True, "start": 0.5, "end": 0.8, "size": 0.05} }, x = xs, y = ys, z = zs ) fig = go.Figure(sur) fig.update_layout( scene = { "xaxis": {"nticks": 20}, "zaxis": {"nticks": 4}, 'camera_eye': {"x": 1, "y": -1.5, "z": 1}, "aspectratio": {"x": 1, "y": 1, "z": 1} }, width=800, height=800) fig.show()
実行してみます。
意図した通りに描画することができました。
意図している関数を描く場合は、x
とy
に値を渡し、z
と対応がついている状態になっているか注意が必要です。また、update_layout
でaspectratio
が設定されている場合には、直感と違う形で描写される可能性があるので、1:1:1
にしておくのが無難そうです。
おわりに
今回はPlotlyの公式ドキュメントのうち3Dプロットを紹介している、3D Surface Plotsに記載の例と、それを元に自分で別の例を描画してみました。
Plotlyの3Dプロットを使うと、とても簡単にインタラクティブな3次元表面が描けるので、この関数どんな表面になってるんだっけ?というときにもPythonで気軽に確認できて良いですね。